package com.pan.games.info;

import java.util.concurrent.SynchronousQueue;

/**
 * 举个比较常见的例子:
 * 某电商有交易和邮件两套系统，当一个交易完成时，给用户发一封确认邮件。这里
 * 交易系统和邮件系统显然是两个优先级的东西，交易系统要求很高的实时性，而邮件系统则不必，为了合理利用服务器资源，应当把这两套系统分离，合理的做法
 * 是，交易完成时，交易系统生成一个发邮件的任务，丢到queue中，而邮件系统监听在queue的另一端，用一个相对较低的速度处理queue中的发邮件
 *
 * 多线程环境中，通过队列可以很容易实现数据共享，比如经典的“生产者”和“消费者”模型中，通过队列可以很便利地实现两者之间的数据共享。
 * 假设我们有若干生产者线程，另外又有若干个消费者线程。如果生产者线程需要把准备好的数据共享给消费者线程，利用队列的方式来传递数据，
 * 就可以很方便地解决他们之间的数据共享问题。但如果生产者和消费者在某个时间段内，万一发生数据处理速度不匹配的情况呢？
 * 理想情况下，如果生产者产出数据的速度大于消费者消费的速度，并且当生产出来的数据累积到一定程度的时候，那么生产者必须暂停等待一下（阻塞生产者线程），
 * 以便等待消费者线程把累积的数据处理完毕，反之亦然。
 *
 * 然而，在concurrent包发布以前，在多线程环境下，我们每个程序员都必须去自己控制这些细节，尤其还要兼顾效率和线程安全，而这会给我们的程序带来不小的复杂度。
 * 好在此时，强大的concurrent包横空出世了，而他也给我们带来了强大的BlockingQueue。
 * （在多线程领域：所谓阻塞，在某些情况下会挂起线程（即阻塞），一旦条件满足，被挂起的线程又会自动被唤醒）
 *
 * @author by panstark
 * @description
 * @notice
 * @date 2020/12/16
 */
public class BlockingQueueInfo {


    /**
     *    Java并发包中的阻塞队列一共7个，当然他们都是线程安全的。
     *
     * 　　ArrayBlockingQueue：一个由数组结构组成的有界阻塞队列。
     *
     * 　　LinkedBlockingQueue：一个由链表结构组成的有界阻塞队列。
     *
     * 　　PriorityBlockingQueue：一个支持优先级排序的无界阻塞队列。
     *
     * 　　DelayQueue：一个使用优先级队列实现的无界阻塞队列。
     *
     * 　　SynchronousQueue：一个不存储元素的阻塞队列。
     *
     * 　　LinkedTransferQueue：一个由链表结构组成的无界阻塞队列。
     *
     * 　　LinkedBlockingDeque：一个由链表结构组成的双向阻塞队列。（摘自《Java并发编程的艺术》）
     */


    /**

     *
     * SynchronousQueue 也是一个队列来的，但它的特别之处在于它内部没有容器，一个生产线程，当它生产产品（即put的时候），
     * 如果当前没有人想要消费产品(即当前没有线程执行take)，此生产线程必须阻塞，等待一个消费线程调用take操作，take操作将会唤醒该生产线程，
     * 同时消费线程会获取生产线程的产品（即数据传递），这样的一个过程称为一次配对过程(当然也可以先take后put,原理是一样的)
     */
    public static void testSynchronousQueue() throws InterruptedException {
        final SynchronousQueue<Integer> queue = new SynchronousQueue<Integer>();

        Thread putThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("put thread start");
                try {
                    queue.put(1);
                    queue.put(2);
                    queue.put(3);
                } catch (InterruptedException e) {
                }
                System.out.println("put thread end");
            }
        });

        Thread takeThread = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("take thread start");
                try {
                    System.out.println("take from putThread: " + queue.take());
                    System.out.println("take from putThread: " + queue.take());
                    System.out.println("take from putThread: " + queue.take());
                } catch (InterruptedException e) {
                }
                System.out.println("take thread end");
            }
        });

        putThread.start();
        Thread.sleep(1000);
        takeThread.start();

    }

    /**
     * * DelayQueue是一个无界的BlockingQueue，用于放置实现了Delayed接口的对象，其中的对象只能在其到期时才能从队列中取走。
     *      * 这种队列是有序的，即队头对象的延迟到期时间最长。注意：不能将null元素放置到这种队列中。
     *
     *   用途
     *   1. 淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单。
     * 　2. 饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。
     *
     * 　3.关闭空闲连接。服务器中，有很多客户端的连接，空闲一段时间之后需要关闭之。
     *
     * 　4.缓存。缓存中的对象，超过了空闲时间，需要从缓存中移出。
     *
     * 　5.任务超时处理。在网络协议滑动窗口请求应答式交互时，处理超时未响应的请求等。
     */
    public static void testDelayQueue(){


    }

    /**
     * LinkedTransferQueue是 SynchronousQueue 和 LinkedBlockingQueue 的合体，性能比 LinkedBlockingQueue 更高（没有锁操作），
     * 比 SynchronousQueue能存储更多的元素。
     *
     * LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列，LinkedTransferQueue多了tryTransfer和transfer方法。
     *
     * LinkedTransferQueue采用一种预占模式。意思就是消费者线程取元素时，如果队列不为空，则直接取走数据，若队列为空，那就生成一个节点（节点元素为null）入队，然后消费者线程被等待在这个节点上，后面生产者线程入队时发现有一个元素为null的节点，生产者线程就不入队了，直接就将元素填充到该节点，并唤醒该节点等待的线程，被唤醒的消费者线程取走元素，从调用的方法返回。我们称这种节点操作为“匹配”方式。
     *
     * LinkedTransferQueue是ConcurrentLinkedQueue、SynchronousQueue（公平模式下转交元素）、LinkedBlockingQueue（阻塞Queue的基本方法）的超集。而且LinkedTransferQueue更好用，因为它不仅仅综合了这几个类的功能，同时也提供了更高效的实现。
     */


    /**
     *java6增加了两种容器类型，Deque和BlockingDeque,它们分别对Queue和BlockingQueue进行了扩展。
     * Deque是一个双端队列，deque(双端队列) 是 "Double Ended Queue" 的缩写。因此，双端队列是一个你可以从任意一端插入或者抽取元素的队列。实现了在队列头和队列尾的高效插入和移除。
     * BlockingDeque 类是一个双端队列，在不能够插入元素时，它将阻塞住试图插入元素的线程；在不能够抽取元素时，它将阻塞住试图抽取的线程。
     * 正如阻塞队列使用与生产者-消费者模式，双端队列同样适用于另一种相关模式，即工作密取。在生产者-消费者设计中，所有消费者有一个共享的工作队列，而在工作密取设计中，每个消费者都有各自的双端队列。如果一个消费者完成了自己双端队列中的全部工作，那么它可以从其它消费者双端队列末尾秘密地获取工作。密取工作模式比传统的生产者-消费者模式具有更高的可伸缩性，这是因为工作者线程不会在单个共享的任务队列上发生竞争。在大多数时候，它们都只是访问自己的双端队列，从而极大地减少了竞争。当工作者线程需要访问另一个队列时，它会从队列的尾部而不是头部获取工作，因此进一步降低了队列上的竞争程度。
     *
     *
     * LinkedBlockingDeque是双向链表实现的双向并发阻塞队列。该阻塞队列同时支持FIFO和FILO两种操作方式，即可以从队列的头和尾同时操作(插入/删除)；并且，该阻塞队列是支持线程安全。
     * 此外，LinkedBlockingDeque还是可选容量的(防止过度膨胀)，即可以指定队列的容量。如果不指定，默认容量大小等于Integer.MAX_VALUE。
     */

    /**
     * BlockingQueue是JDK1.5出现的接口，它在原来的Queue接口基础上提供了更多的额外功能：
     * 当获取队列中的头部元素时，如果队列为空，那么它将会使执行线程处于等待状态；
     * 当添加一个元素到队列的尾部时，如果队列已经满了，那么它同样会使执行的线程处于等待状态。
     *
     * 针对于相同的操作提供了4种不同的形式。
     *
     * 该四种形式分别为：
     *
     * 抛出异常
     * 返回一个特殊值(可能是null或者是false，取决于具体的操作)
     * 阻塞当前执行直到其可以继续
     * 当线程被挂起后，等待最大的时间，如果一旦超时，即使该操作依旧无法继续执行，线程也不会再继续等待下去。
     *
     */


}
